/*******************************************************************************
 * Copyright (c) 2001-2003 Boris Pruessmann and others. All rights reserved.
 * This program and the accompanying materials are made available under the
 * terms of the Common Public License v0.5 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/cpl-v05.html
 *
 * Contributors: Boris Pruessmann - Initial implementation. David Corbin - added
 * several status: BRANCHED_TO, REOPENED_FOR_ADD, OPENED_FOR_DELETE
 ******************************************************************************/
package net.sourceforge.perforce.core.internal.api;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import net.sourceforge.perforce.api.PerforceApiPlugin;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;

import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

/**
 * @version $Revision: 489 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 * @author <a href="mailto:dcorbin@users.sourceforge.net">David Corbin</a>
 */
public class PerforceStatus {
  //----------------------------------------------------------------------------
  // Public Constants

  /** NO COMMENT */
  public static final IStatus OK = new Status(IStatus.OK, PerforceApiPlugin.ID, 1000, "", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus FILES_UPTODATE =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1001, "FILE(S) UP-TO-DATE", null);//$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus OPENED_FOR_EDIT =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1002, "OPENED FOR EDIT", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus WAS_EDIT_REVERTED =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1003, "WAS EDIT REVERTED", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus WAS_ADD_ABANDONED =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1004, "WAS ADD ABANDONED", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus OPENED_FOR_ADD =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1005, "OPENED FOR ADD", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus CURRENTLY_OPENED_FOR_ADD =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1006, "CURRENTLY OPENED FOR ADD", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus CURRENTLY_OPENED_FOR_EDIT =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1007, "CURRENTLY OPENED FOR EDIT", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus UPDATING =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1008, "UPDATING", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus REOPENED_CHANGE =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1009, "REOPENED CHANGE", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus NOTHING_CHANGED =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1010, "NOTHING CHANGED", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus REFRESHING =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1011, "REFRESHING", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus ADDED_AS =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1012, "ADDED AS", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus DELETED_AS =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1013, "DELETED AS", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus BRANCHED_TO =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1014, "BRANCH/SYNC", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus REOPENED_FOR_ADD =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1015, "REOPENED FOR ADD", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus OPENED_FOR_DELETE =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1016, "OPENED FOR DELETE", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus WAS_DELETE_REVERTED =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1017, "WAS DELETE REVERTED", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus NO_FILES_TO_RESOLVE =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1018, "NO FILE(S) TO RESOLVE", null); //$NON-NLS-1$

  /** Perforce Message: 'was branch, deleted' */
  public static final IStatus WAS_BRANCH_DELETED =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1019, "WAS BRANCH DELETED", null); //$NON-NLS-1$

  /** Perforce Message: 'was edit, unlocked and reverted. */
  public static final IStatus WAS_EDIT_UNLOCKED_AND_REVERTED =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1020, "WAS EDIT UNLOCKED AND REVERTED", null);//$NON-NLS-1$

  /** Perforce Message: 'was edit, unlocked and reverted. */
  public static final IStatus WAS_INTEGRATE_REVERTED =
      new Status(IStatus.OK, PerforceApiPlugin.ID, 1021, "WAS INTEGRATE REVERTED", null);//$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus INFO = new Status(IStatus.INFO, PerforceApiPlugin.ID, 2000, "", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus EMPTY_ASSUMING_TEXT =
      new Status(IStatus.INFO, PerforceApiPlugin.ID, 2001, "EMPTY ASSUMING TEXT", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus ALSO_OPENED_BY =
      new Status(IStatus.INFO, PerforceApiPlugin.ID, 2002, "ALSO OPENED BY", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus MUST_SYNC_RESOLVE_BEFORE_SUBMITTING =
      new Status(IStatus.INFO, PerforceApiPlugin.ID, 2003,
          "MUST SYNC/RESOLVE BEFORE SUBMITTING", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus LOCKED_BY =
      new Status(IStatus.INFO, PerforceApiPlugin.ID, 2004, "LOCKED BY", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus IS_OPENED_AND_NOT_BEING_CHANGED =
      new Status(IStatus.INFO, PerforceApiPlugin.ID, 2005, "IS OPENED AND NOT BEING CHANGED", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus NO_SUCH_FILES =
      new Status(IStatus.INFO, PerforceApiPlugin.ID, 2006, "NO SUCH FILE(S)", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus NO_FILES_RESOLVED =
      new Status(IStatus.INFO, PerforceApiPlugin.ID, 2007, "NO FILE(S) RESOLVED", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus FILES_NOT_OPENED_FOR_EDIT =
      new Status(IStatus.INFO, PerforceApiPlugin.ID, 2009, "FILE(S) NOT OPENED FOR EDIT", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus FILES_NOT_IN_CLIENT_VIEW =
      new Status(IStatus.INFO, PerforceApiPlugin.ID, 2010, "FILE(S) NOT IN CLIENT VIEW", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus ADD_DELETED_FILE =
      new Status(IStatus.INFO, PerforceApiPlugin.ID, 2011, "ADD DELETED FILE", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus ERROR =
      new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4000, "", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus MUST_RESOLVE_BEFORE_SUBMITTING =
      new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4001, "MUST RESOLVE BEFORE SUBMITTING", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus MUST_RESOLVE =
      new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4002, "MUST RESOLVE", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus CANT_ADD_EXCLUSIVE_FILE_ALREADY_OPENED =
      new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4003,
          "CAN'T ADD EXCLUSIVE FILE ALREADY OPENED", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus ALREADY_LOCKED_BY =
      new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4004, "ALREADY LOCKED BY", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus MUST_REFER_TO_CLIENT =
      new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4005, "MUST REFER TO CLIENT", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus FILES_NOT_ON_CLIENT =
      new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4006, "FILE(S) NOT ON CLIENT", null); //$NON-NLS-1$

  /** NO COMMENT */
  public static final IStatus FILES_NOT_OPENED_ON_THIS_CLIENT =
      new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4007,
          "FILE(S) NOT OPENED ON THIS CLIENT", null);//$NON-NLS-1$

  /** Perforce Messsage: 'No such changelist' */
  public static final IStatus NO_SUCH_CHANGELIST =
      new Status(IStatus.ERROR, PerforceApiPlugin.ID, 4008, "NO SUCH CHANGELIST", null); //$NON-NLS-1$

  // ---------------------------------------------------------------------------
  // Private Constants

  /** NO COMMENT */
  private static final String[] KNOWN_TOKENS = {"INTEGRATE", "FILE(S)", //$NON-NLS-1$
      "UP-TO-DATE", //$NON-NLS-1$
      "WAS", //$NON-NLS-1$
      "EDIT", //$NON-NLS-1$
      "REVERTED", //$NON-NLS-1$
      "OPENED", //$NON-NLS-1$
      "FOR", //$NON-NLS-1$
      "ADD", //$NON-NLS-1$
      "ABANDONED", //$NON-NLS-1$
      "EMPTY", //$NON-NLS-1$
      "ASSUMING", //$NON-NLS-1$
      "TEXT", //$NON-NLS-1$
      "CURRENTLY", //$NON-NLS-1$
      "ALSO", //$NON-NLS-1$
      "BY", //$NON-NLS-1$
      "MUST", //$NON-NLS-1$
      "RESOLVE", //$NON-NLS-1$
      "BEFORE", //$NON-NLS-1$
      "SUBMITTING", //$NON-NLS-1$
      "SYNC/RESOLVE", //$NON-NLS-1$
      "BRANCH/SYNC", //$NON-NLS-1$
      "CAN'T", //$NON-NLS-1$
      "EXCLUSIVE", //$NON-NLS-1$
      "FILE", //$NON-NLS-1$
      "ALREADY", //$NON-NLS-1$
      "LOCKED", //$NON-NLS-1$
      "UPDATING", //$NON-NLS-1$
      "REOPENED", //$NON-NLS-1$
      "CHANGE", //$NON-NLS-1$
      "NOTHING", //$NON-NLS-1$
      "CHANGED", //$NON-NLS-1$
      "REFER", //$NON-NLS-1$
      "TO", //$NON-NLS-1$
      "CLIENT", //$NON-NLS-1$
      "ADDED", //$NON-NLS-1$
      "AS", //$NON-NLS-1$
      "IS", //$NON-NLS-1$
      "AND", //$NON-NLS-1$
      "NOT", //$NON-NLS-1$
      "BEING", //$NON-NLS-1$
      "DELETED", //$NON-NLS-1$
      "DELETE", //$NON-NLS-1$
      "NO", //$NON-NLS-1$
      "SUCH", //$NON-NLS-1$
      "REFRESHING", //$NON-NLS-1$
      "RESOLVED", //$NON-NLS-1$
      "ON", //$NON-NLS-1$
      "IN", //$NON-NLS-1$
      "VIEW", //$NON-NLS-1$
      "BRANCH", //$NON-NLS-1$
      "THIS", //$NON-NLS-1$
      "UNLOCKED", //$NON-NLS-1$
      "CHANGELIST", //$NON-NLS-1$
  };

  // ------------------------------------------------------------------- Private
  // Static Variables

  /** Will contain a sorted list of all known tokens. */
  private static Set<String> knownTokensSet;
  /** Will contain a sorted status map. */
  private static Map<String, IStatus> statusMap;

  // -------------------------------------------------------------------- Static
  // Initializer Block
  static {
    knownTokensSet = Sets.newHashSet(KNOWN_TOKENS);

    statusMap = Maps.newTreeMap();

    // IStatus.OK
    statusMap.put(FILES_UPTODATE.getMessage(), FILES_UPTODATE);
    statusMap.put(OPENED_FOR_EDIT.getMessage(), OPENED_FOR_EDIT);
    statusMap.put(WAS_EDIT_REVERTED.getMessage(), WAS_EDIT_REVERTED);
    statusMap.put(WAS_ADD_ABANDONED.getMessage(), WAS_ADD_ABANDONED);
    statusMap.put(OPENED_FOR_ADD.getMessage(), OPENED_FOR_ADD);
    statusMap.put(CURRENTLY_OPENED_FOR_ADD.getMessage(), CURRENTLY_OPENED_FOR_ADD);
    statusMap.put(CURRENTLY_OPENED_FOR_EDIT.getMessage(), CURRENTLY_OPENED_FOR_EDIT);
    statusMap.put(UPDATING.getMessage(), UPDATING);
    statusMap.put(REOPENED_CHANGE.getMessage(), REOPENED_CHANGE);
    statusMap.put(NOTHING_CHANGED.getMessage(), NOTHING_CHANGED);
    statusMap.put(REFRESHING.getMessage(), REFRESHING);
    statusMap.put(ADDED_AS.getMessage(), ADDED_AS);
    statusMap.put(DELETED_AS.getMessage(), DELETED_AS);
    statusMap.put(BRANCHED_TO.getMessage(), BRANCHED_TO);
    statusMap.put(REOPENED_FOR_ADD.getMessage(), REOPENED_FOR_ADD);
    statusMap.put(OPENED_FOR_DELETE.getMessage(), OPENED_FOR_DELETE);
    statusMap.put(WAS_DELETE_REVERTED.getMessage(), WAS_DELETE_REVERTED);
    statusMap.put(NO_FILES_TO_RESOLVE.getMessage(), NO_FILES_TO_RESOLVE);
    statusMap.put(WAS_BRANCH_DELETED.getMessage(), WAS_BRANCH_DELETED);
    statusMap.put(WAS_EDIT_UNLOCKED_AND_REVERTED.getMessage(), WAS_EDIT_UNLOCKED_AND_REVERTED);
    statusMap.put(WAS_INTEGRATE_REVERTED.getMessage(), WAS_INTEGRATE_REVERTED);

    // IStatus.INFO
    statusMap.put(EMPTY_ASSUMING_TEXT.getMessage(), EMPTY_ASSUMING_TEXT);
    statusMap.put(ALSO_OPENED_BY.getMessage(), ALSO_OPENED_BY);
    statusMap.put(MUST_SYNC_RESOLVE_BEFORE_SUBMITTING.getMessage(),
        MUST_SYNC_RESOLVE_BEFORE_SUBMITTING);
    statusMap.put(LOCKED_BY.getMessage(), LOCKED_BY);
    statusMap.put(IS_OPENED_AND_NOT_BEING_CHANGED.getMessage(), IS_OPENED_AND_NOT_BEING_CHANGED);
    statusMap.put(NO_SUCH_FILES.getMessage(), NO_SUCH_FILES);
    statusMap.put(NO_FILES_RESOLVED.getMessage(), NO_FILES_RESOLVED);
    statusMap.put(FILES_NOT_OPENED_FOR_EDIT.getMessage(), FILES_NOT_OPENED_FOR_EDIT);
    statusMap.put(FILES_NOT_IN_CLIENT_VIEW.getMessage(), FILES_NOT_IN_CLIENT_VIEW);
    statusMap.put(ADD_DELETED_FILE.getMessage(), ADD_DELETED_FILE);

    // IStatus.ERROR
    statusMap.put(MUST_RESOLVE_BEFORE_SUBMITTING.getMessage(), MUST_RESOLVE_BEFORE_SUBMITTING);
    statusMap.put(MUST_RESOLVE.getMessage(), MUST_RESOLVE);
    statusMap.put(CANT_ADD_EXCLUSIVE_FILE_ALREADY_OPENED.getMessage(),
        CANT_ADD_EXCLUSIVE_FILE_ALREADY_OPENED);
    statusMap.put(ALREADY_LOCKED_BY.getMessage(), ALREADY_LOCKED_BY);
    statusMap.put(MUST_REFER_TO_CLIENT.getMessage(), MUST_REFER_TO_CLIENT);
    statusMap.put(FILES_NOT_ON_CLIENT.getMessage(), FILES_NOT_ON_CLIENT);
    statusMap.put(FILES_NOT_OPENED_ON_THIS_CLIENT.getMessage(), FILES_NOT_OPENED_ON_THIS_CLIENT);
    statusMap.put(NO_SUCH_CHANGELIST.getMessage(), NO_SUCH_CHANGELIST);
  }

  // -----------------------------------------------------------------------
  // Public Static Methods

  /**
   * Decodes the given perforce message into a status object.
   *
   * @param perforceString the message provided by perforce.
   * @param severity the severity.
   * @return the decoded status object.
   */
  public static IStatus decode(String perforceString, int severity) {
    int pos = perforceString.lastIndexOf(" - "); //$NON-NLS-1$
    if (pos == -1) {
      return new Status(severity, OK.getPlugin(), severity, perforceString.trim(), OK
          .getException());
    }

    StringBuilder buffer = new StringBuilder();
    StringTokenizer tokenizer =
        new StringTokenizer(perforceString.substring(pos + 3).toUpperCase(), " .,;\n");
    while (tokenizer.hasMoreTokens()) {
      final String token = tokenizer.nextToken();
      if (knownTokensSet.contains(token)) {
        buffer.append(token);
      }

      if (buffer.length() > 0 && buffer.charAt(buffer.length() - 1) != ' ') {
        buffer.append(' '); //$NON-NLS-1$
      }
    }

    IStatus result = null;

    String key = buffer.toString().trim();
    IStatus status = statusMap.get(key);
    if (status == null) {
      result =
          new Status(IStatus.ERROR, PerforceApiPlugin.ID, 999, "Unknown result: " + perforceString
              + "<" + key + ">", null);
    } else {
      result =
          new Status(status.getSeverity(), status.getPlugin(), status.getCode(), perforceString
              .trim(), status.getException());
    }

    return result;
  }
}
